﻿namespace OpenIddictService.Controllers
{
    using Microsoft.AspNetCore;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.IdentityModel.Tokens;
    using OpenIddict.Abstractions;
    using OpenIddict.Server.AspNetCore;
    using OpenIddictService.Models;
    using System.Security.Claims;
    using static OpenIddict.Abstractions.OpenIddictConstants;

    /// <summary>
    /// Defines the <see cref="ConnectController" />
    /// </summary>
    public class ConnectController : Controller
    {
        /// <summary>
        /// Defines the myuser
        /// </summary>
        internal UserInfo myuser;

        /// <summary>
        /// Initializes a new instance of the <see cref="ConnectController"/> class.
        /// </summary>
        /// <param name="userInfo">The userInfo<see cref="UserInfo"/></param>
        public ConnectController(UserInfo userInfo)
        {
            myuser = userInfo;
        }

        /// <summary>
        /// The authorize
        /// </summary>
        /// <returns>The <see cref="Task{IActionResult}"/></returns>
        [HttpGet("~/connect/authorize")]
        [HttpPost("~/connect/authorize")]
        [IgnoreAntiforgeryToken]
        public async Task<IActionResult> authorize()
        {

            var request = HttpContext.GetOpenIddictServerRequest() ??
           throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");
            var result = await HttpContext.AuthenticateAsync();
            if (!result.Succeeded)
            {
                string url = Request.PathBase + Request.Path + QueryString.Create(
                    Request.HasFormContentType ? Request.Form : Request.Query);

                return Challenge(new AuthenticationProperties
                {
                    RedirectUri = url
                });
            }

            long sid = long.Parse(result.Principal.GetClaim(ClaimTypes.Sid));
            if (myuser != null && myuser.id == sid)
            {
                var identity = new ClaimsIdentity(authenticationType: TokenValidationParameters.DefaultAuthenticationType);
                identity.SetClaim(Claims.Subject, myuser.Gid.ToString());
                identity.SetClaim(Claims.PhoneNumber, myuser.phone);
                identity.SetClaim(Claims.Nickname, myuser.account.ToString());
                identity.SetClaim(Claims.PreferredUsername, myuser.name);

                identity.SetClaim(ClaimTypes.Sid, myuser.id.ToString());
                identity.SetScopes(request.GetScopes());
                identity.SetAuthorizationId(myuser.id.ToString());
                identity.SetDestinations(claim => [Destinations.AccessToken, Destinations.IdentityToken]);

                identity.SetClaim(Claims.Private.CodeChallenge, request.CodeChallenge);//校验需要
                identity.SetClaim(Claims.Private.CodeChallengeMethod, request.CodeChallengeMethod);//校验需要

                return SignIn(new ClaimsPrincipal(identity), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
            }

            string newurl = Request.PathBase + Request.Path + QueryString.Create(
                    Request.HasFormContentType ? Request.Form : Request.Query);

            return Challenge(new AuthenticationProperties
            {
                RedirectUri = newurl
            });
        }

        /// <summary>
        /// The Token
        /// </summary>
        /// <returns>The <see cref="Task{IActionResult}"/></returns>
        [HttpGet("~/connect/token")]
        [HttpPost("~/connect/token")]
        [IgnoreAntiforgeryToken]
        public async Task<IActionResult> Token()
        {
            var request = HttpContext.GetOpenIddictServerRequest() ??
                throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");

            if (request.IsAuthorizationCodeGrantType() || request.IsRefreshTokenGrantType())
            {
                // Retrieve the claims principal stored in the authorization code/refresh token.
                var result = await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
                var identity = new ClaimsIdentity(
                    result.Principal.Claims,
                    authenticationType: TokenValidationParameters.DefaultAuthenticationType);

                return SignIn(new ClaimsPrincipal(identity), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
            }
            throw new InvalidOperationException("The specified grant type is not supported.");
        }

        /// <summary>
        /// The Logout
        /// </summary>
        /// <returns>The <see cref="IActionResult"/></returns>
        [HttpGet("~/connect/logout")]
        public IActionResult Logout()
        {
            return View();
        }

        /// <summary>
        /// The LogoutPost
        /// </summary>
        /// <returns>The <see cref="Task{IActionResult}"/></returns>
        [HttpPost("~/connect/logout"), ValidateAntiForgeryToken]
        public async Task<IActionResult> LogoutPost()
        {
            await HttpContext.SignOutAsync();

            return SignOut(
                authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
                properties: new AuthenticationProperties
                {
                    RedirectUri = "/"
                });
        }
    }
}
